<?php
/*
 *  Copyright (C) 2009 Mauro Rocco "fireantology@gmail.com"
 *
 *  This file is part of Ptwix.
 *
 *  PTwix is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  PTwix is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with PTwix.  If not, see <http://www.gnu.org/licenses/>.
 */


/*
 * Configuration parameters
*/

$url_path="http://localhost/ptwix/trunk/";
$cache_path="/home/mauro/www/ptwix/trunk/cache/";
$abs_path="/home/mauro/www/ptwix/trunk/";
$username="ptwix";

$consumer_key = "";
$consumer_secret = "";
$access_token="";
$access_token_secret="";


/***************************************************************************
 * ----------------- START PTWIX CORE, BE CAREFUL --------------------------
***************************************************************************/



require($abs_path.'lib/twitteroauth/OAuth.php');
require($abs_path.'lib/twitteroauth/twitterOAuth.php');

/**
 * Implements a Twitter grabber
 */
class PtwiX {
    public  $twitter_base  = 'http://twitter.com/statuses/';
    public  $twitter_base_api  = 'http://api.twitter.com/1/';
    private $preurl_user="http://twitter.com/";
    private $search_url="http://search.twitter.com/search.json?q=";
    private $instance_name;
    private $username;
    private $path;
    private $theme;
    private $timeline;
    private $cache_folder;
    private $width;
    private $height;
    private $async_filename;
    private $useCurl=true;
    private $string_to_search="php&result_type=mixed";
    private $searchTitle="";
    private $abs_path;
    private $cache_refresh_interval=60;
    private $max_tweets_number=20;

    private $consumer_key;
    private $consumer_secret;
    private $access_token;
    private $access_token_secret;

    public static $USER_TIMELINE=0;
    public static $FRIENDS_TIMELINE=1;
    public static $SEARCH=2;

    /**
     * Create a Twitter grabber
     * @param $instance_name
     * @param $timeline The type of timeline to show (User timeline or Friends timeline) use static variable (Ptwix::USER_TIMELINE)
     * @param $theme Theme folder name
     */

    public function  __construct($instance_name, $timeline=1, $theme="gray-blue") {

        if(!$this->validateParameter($theme)) die("The theme name must contains only [a-zA-Z0-9_-] ");
        if(!$this->validateParameter($instance_name)) die("The instance name must contains only [a-zA-Z0-9_-] ");

        global $username;
	$this->username=$username;

        global $url_path;
	$this->path=$url_path;

	global $cache_path;
        $this->cache_folder=$cache_path;

	global $abs_path;  
	$this->abs_path=$abs_path;

        global $consumer_key;
        $this->consumer_key=$consumer_key;

        global $consumer_secret;
        $this->consumer_secret=$consumer_secret;

        global $access_token;
        $this->access_token=$access_token;

        global $access_token_secret;
        $this->access_token_secret=$access_token_secret;
        
	$this->theme=$theme;
        $this->timeline=$timeline;
        $this->instance_name=$instance_name;
        $this->width=400;
        $this->height=265;
        $this->async_filename="PtwiX_reader.php";
    }

    /**
     * Set dimension of PtwiX box
     * @param $width box width
     * @param $height box height
     */

    public function setDimension($width, $height) {
        $this->width=$width;
        $this->height=$height;
    }

    /**
     * Activate or Deactivate curl request
     * @param $boolean true for Using curl function
     */

    public function useCurl($boolean) {
        $this->useCurl=$boolean;
    }


    /**
     * Setting a string for twitter search
     * @param $string the search string (q=twitter&rpp=20) 
     */

    public function setSearchString($string) {
        $this->string_to_search=$string;
    }

    /**
     * Set the refreshing interval of the cache in second
     * ATTENTION! If you put a value less than 30 seconds the twitter server could
     * stop you request. 
     * @param $cache_refresh_interval refreshing time of the cache in seconds
     */

    public function setCacheRefreshTime($cache_refresh_interval) {
        $this->cache_refresh_interval=$cache_refresh_interval;
    }

    private function validateParameter($string) {
        return preg_match("/^[a-zA-Z0-9_-]+$/",$string);
    }

    /**
     * Print html code for css include
     */

    public function printCssRef() {
        echo '<link href="'.$this->path.'themes/'.$this->theme.'/PtwiX.css" rel="stylesheet" type="text/css" />';
    }

    private function parseText($text) {
        $text.=" ";
        $text=preg_replace("/http:\/\/([^ ]+) /", "<a href=\"http://$1\" target=\"_blank\">http://$1</a> ", $text);
        $text=preg_replace("/@([a-zA-z0-9_]+)/", "@<a href=\"".$this->preurl_user."$1\" target=\"_blank\">$1</a> ", $text);
        $text=preg_replace("/#([a-zA-z0-9_]+)/", "#<a href=\"".$this->search_url."$1\" target=\"_blank\">$1</a> ", $text);
        return $text;
    }


    private function dateFormatting($date) {
        $temp=strtotime($date);
        $date=date("d M Y H:i", $temp);
        return $date;
    }

    /**
     * Get Twitter post as html
     * @param $timeline
     * @return string post html code
     */

    public function  getData($timeline) {
		$template = $this->getTemplate();
		$output=str_replace('{{searchtitle}}',$this->searchTitle,$template);
		$start=strpos($output,"{{cycle}}");
		$end=strpos($output,"{{endcycle}}");
		$cycle=substr($output,$start+9,$end-$start-9);
		return $this->parseDataTemplate($cycle);
    }

    private function parseDataTemplate($cycle){
        $messages="";
        $response=$this->buildMessagesArray($this->timeline);
        foreach ($response as $status) {
                $temp=str_replace('{{profile_image_url}}',$status['profile_image_url'],$cycle);
                $temp=str_replace('{{user_screen_name}}',$status['user_screen_name'],$temp);
                $temp=str_replace('{{user_link_profile}}',$this->preurl_user.$status['user_screen_name'],$temp);
                $temp=str_replace('{{status_text}}',$this->parseText($status['formatted_text']),$temp);
                $temp=str_replace('{{created_at}}',$this->dateFormatting($status['created_at']),$temp);
                $temp=str_replace('{{reply_to}}',$this->dateFormatting($status['in_reply_to_screen_name']),$temp);
                $temp=str_replace('{{theme}}',$this->theme,$temp);
                $temp=str_replace('{{width}}',$this->width,$temp);
                $temp=str_replace('{{height}}',$this->height,$temp);
                $temp=str_replace('{{theme_path}}',$this->path."themes/".$this->theme,$temp);
                $temp=str_replace('{{instance_name}}',$this->instance_name,$temp);
                $messages.="\n".$temp;
        }
        return $messages;
    }


    private function getTemplate(){
            $file_name=$this->abs_path.'themes/'.$this->theme.'/PtwiX.tpl';
            $file_template = @fopen($file_name, 'r');
            if(!$file_template){
                echo "Template file not found in path ".$file_name;
                exit();
            }
            $template = fread($file_template, filesize($file_name));
            return $template;
    }


    private function getBox() {
        $messages="";

        $template = $this->getTemplate();

        $output=str_replace('{{searchtitle}}',$this->searchTitle,$template);
        $output=str_replace('{{profile_url}}',$this->preurl_user.$this->username,$output);

        $start=strpos($output,"{{cycle}}");
        $end=strpos($output,"{{endcycle}}");

        $pre_cycle=substr($output,0,$start);
        $cycle=substr($output,$start+9,$end-$start-9);
        $post_cycle=substr($output,$end+12,strlen($output));

        $pre_cycle=str_replace('{{theme}}',$this->theme,$pre_cycle);
        $pre_cycle=str_replace('{{width}}',$this->width,$pre_cycle);
        $pre_cycle=str_replace('{{height}}',$this->height,$pre_cycle);
        $pre_cycle=str_replace('{{theme_path}}',$this->path."themes/".$this->theme,$pre_cycle);
        $pre_cycle=str_replace('{{instance_name}}',$this->instance_name,$pre_cycle);
        $pre_cycle=str_replace('{{javascript}}',$this->returnJs(),$pre_cycle);

        $post_cycle=str_replace('{{theme}}',$this->theme,$post_cycle);
        $post_cycle=str_replace('{{width}}',$this->width,$post_cycle);
        $post_cycle=str_replace('{{height}}',$this->height,$post_cycle);
        $post_cycle=str_replace('{{theme_path}}',$this->path."themes/".$this->theme,$post_cycle);
        $post_cycle=str_replace('{{instance_name}}',$this->instance_name,$post_cycle);
        $post_cycle=str_replace('{{javascript}}',$this->returnJs(),$post_cycle);

        $messages.= $pre_cycle;
        $messages.= $post_cycle;
        return $messages;
    }

    private function buildMessagesArray($timeline) {
        $messages_array=array();

    $json_object=json_decode(file_get_contents($this->readFile($timeline)));
    if($this->timeline==self::$SEARCH){
        $json_object=$json_object->results;
        foreach ($json_object as $message) {
            $temp=array();
            $temp['id']=$message->{'id'};
            $temp['profile_image_url']=$message->{'profile_image_url'};
            $temp['user_screen_name']=$message->{'from_user'};
            $temp['text']=$message->{'text'};
            $temp['formatted_text']=$message->{'text'};
            $temp['created_at']=$message->{'created_at'};
            $temp['relative_time']=$this->getRelativeTime($temp['created_at']);
            $temp['in_reply_to_screen_name']=$message->{'to_user'};
            $temp['reply_url']=$this->preurl_user."?status=@".$temp['screen_name']."&in_reply_to_status_id=".$temp['id']."&in_reply_to=".$temp['screen_name'];
            $temp['retweet_link']=$this->preurl_user."home/?status=RT+@".$temp['screen_name']."+%0A9 ".$temp['text'];
            $temp['status_url']=$this->preurl_user.$temp['screen_name']."/status/".$temp['id'];
            $messages_array[]=$temp;
        }
    }
    else{
        foreach ($json_object as $message) {
            $temp=array();
            $temp['id']=$message->{'id'};
            $temp['profile_image_url']=$message->{'user'}->{'profile_image_url'};
            $temp['user_screen_name']=$message->{'user'}->{'screen_name'};
            $temp['text']=$message->{'text'};
            $temp['formatted_text']=$message->{'text'};
            $temp['created_at']=$message->{'created_at'};
            $temp['relative_time']=$this->getRelativeTime($temp['created_at']);
            $temp['in_reply_to_screen_name']=$message->{'in_reply_to_screen_name'};
            $temp['reply_url']=$this->preurl_user."?status=@".$temp['screen_name']."&in_reply_to_status_id=".$temp['id']."&in_reply_to=".$temp['screen_name'];
            $temp['retweet_link']=$this->preurl_user."home/?status=RT+@".$temp['screen_name']."+%0A9 ".$temp['text'];
            $temp['status_url']=$this->preurl_user.$temp['screen_name']."/status/".$temp['id'];
            $messages_array[]=$temp;
        }
    }
        
        
        return $messages_array;
    }

    /**
     * Print html/javascript PtiwX box
     */

    public function printBox() {
        echo $this->getBox();
    }

    /**
     * Get JS code for PtwiX interface handler
     */

    function returnJS() {
        $js='
	function addLoadEvent(func) {
	  var oldonload = window.onload;
	  if (typeof window.onload != "function") {
	    window.onload = func;
	  } else {
	    window.onload = function() {
	      if (oldonload) {
		oldonload();
	      }
	      func();
	    }
	  }
	}

	function '.$this->instance_name.'PtwiXCreateXmlHttpReq(handler) {

	var xmlhttp = null;
	try {
	    xmlhttp = new XMLHttpRequest();
	} catch(e) {
	    try {
		xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	    } catch(e) {
		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
	    }
	}
	'.$this->instance_name.'PtwiXonLoading();
	xmlhttp.onreadystatechange = handler;
	return xmlhttp;
	}


	function '.$this->instance_name.'PtwiXHandler()
	{
	if (myRequest.readyState == 4 && myRequest.status == 200)
	{
		'.$this->instance_name.'PtwiXprint(myRequest.responseText);

	}
	else if(myRequest.readyState == 4 && myRequest.status == 404){
	'.$this->instance_name.'PtwiXprint("Pagina not found, check configuration file");
	}
	else if(myRequest.readyState == 4){
	'.$this->instance_name.'PtwiXprint("Server Error");
	}

	}

	function '.$this->instance_name.'PtwiXprint(content){
	document.getElementById(\''.$this->instance_name.'PtwiXOverFlow\').innerHTML=content;
	}

	function '.$this->instance_name.'PtwiXonLoading(){
	document.getElementById(\''.$this->instance_name.'PtwiXOverFlow\').innerHTML=\'<img style="margin-top: '.(($this->height/2)-40).'px;" id="LoadingImage_PtwiX" src="'.$this->path.'themes/'.$this->theme.'/images/ptwix_loading.gif" align="center">\';
	}

	function '.$this->instance_name.'PtwiXdoLoad()
	{
	myRequest = '.$this->instance_name.'PtwiXCreateXmlHttpReq('.$this->instance_name.'PtwiXHandler);
	myRequest.open("POST","'.$this->path.'lib/as/'.$this->async_filename.'");
	myRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
	myRequest.send("&theme='.$this->theme.'&timeline='.$this->timeline.'&instance_name='.$this->instance_name.'&search_string='.$this->string_to_search.'");


	}

	addLoadEvent('.$this->instance_name.'PtwiXdoLoad);'
	;
        return $js;
    }

    private function readFile($timeline) {
        $file_date=$this->cache_folder.$this->instance_name."date.dat";
        $fd = @fopen($file_date, 'r');
        if(!$fd) $this->writeFile($timeline);
        else {
            $date = fread($fd, filesize($file_date));
            fclose($fd);
            if(time()-$date>$this->cache_refresh_interval)  $this->writeFile($timeline);
        }
        $cache_file=$this->cache_folder.$this->instance_name."cache.json";
        return $cache_file;
    }

    private function writeFile($timeline) {
        $messages=$this->requestStatuses($timeline);
        $file=fopen($this->cache_folder.$this->instance_name."cache.json", "w");
        fwrite($file, $messages);
        fclose($file);
        
        $file_date=fopen($this->cache_folder.$this->instance_name."date.dat", "w");
        fwrite($file_date, time());
        fclose($file_date);
        return 1;
    }

    private function requestStatuses($timeline) {
        $string_timeline="";
        $json="";
        if($timeline==self::$FRIENDS_TIMELINE) { $string_timeline = $this -> twitter_base_api . "statuses/friends_timeline.json"; }
        else if($timeline==self::$USER_TIMELINE) { $string_timeline = $this -> twitter_base_api . "statuses/user_timeline.json"; }
        else if($timeline==self::$SEARCH) { 
            $string_timeline = $this -> search_url . $this->string_to_search;
            return file_get_contents($string_timeline);
            }

        $to = new TwitterOAuth($this->consumer_key, $this->consumer_secret, $this->access_token, $this->access_token_secret);
	return $to->OAuthRequest($string_timeline, array("count"=>$this->max_tweets_number), 'GET');

    }

    private function plural($num) {
	    if ($num != 1)
		    return "s";
    }

    private function getRelativeTime($date) {
	    $diff = time() - strtotime($date);
	    if ($diff<60)
		    return $diff . " second" . $this->plural($diff) . " ago";
	    $diff = round($diff/60);
	    if ($diff<60)
		    return $diff . " minute" . $this->plural($diff) . " ago";
	    $diff = round($diff/60);
	    if ($diff<24)
		    return $diff . " hour" . $this->plural($diff) . " ago";
	    $diff = round($diff/24);
	    if ($diff<7)
		    return $diff . " day" . $this->plural($diff) . " ago";
	    $diff = round($diff/7);
	    if ($diff<4)
		    return $diff . " week" . $this->plural($diff) . " ago";
	    return "on " . date("F j, Y", strtotime($date));
    }

}
?>
